package com.mingke.chat.handler;

import com.google.gson.Gson;
import com.mingke.chat.message.EasyChatMessage;
import com.mingke.chat.message.logic.EasyChatOfflineLogic;
import com.mingke.chat.message.request.EasyChatReportInfo;
import com.mingke.chat.message.request.EasyChatRequest;
import com.mingke.chat.server.EasyChatClientChannelTool;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Date;

/**
 * @author mingke
 * @function 读数据的回调
 * @date 2021/12/14
 */
public class ReadHandler implements CompletionHandler<Integer, ByteBuffer> {
    private AsynchronousSocketChannel socketChannel;

    public ReadHandler(AsynchronousSocketChannel channel) {
        this.socketChannel = channel;
    }

    @Override
    public void completed(Integer result, ByteBuffer buffer) {
        if(result == -1) {
            //断开连接的话，就不用再去监听了
            Integer number = EasyChatClientChannelTool.instance.removelChannel(socketChannel);
            try {
                socketChannel.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            if(number == null) {
                return;  //用户没有存档，不属于系统服务范围内，直接返回，不用执行逻辑
            }
            EasyChatReportInfo reportInfo = new EasyChatReportInfo(number);
            //执行下线逻辑
            EasyChatOfflineLogic offlineLogic = new EasyChatOfflineLogic();
            offlineLogic.doLogic(reportInfo);
        }else {
            buffer.flip();
            messageNormalization(buffer);
            buffer.clear();
            //继续监听回调
            socketChannel.read(buffer, buffer, this);
        }
    }

    @Override
    public void failed(Throwable exc, ByteBuffer attachment) {

    }

    /**
     * 数据格式化
     * @param buffer 原始的ByteBuffer
     * @return 按通讯协议规则解析过的消息本体
     */
    public void messageNormalization(ByteBuffer buffer) {
        int length = buffer.limit();
        byte bytes[] = new byte[length];
        buffer.get(bytes, 0, length);
        //开始解析，消息内容为空的话，最小长度为19，如果小于19消息就不管了
        if(length > 19) {
            int index = 0;
            /** 魔数*/
            for(int i = 0; i < EasyChatMessage.getMagicContent().length; i++, index++) {
                if(bytes[index] != EasyChatMessage.getMagicContent()[i]) {
                    return;
                }
            }
            /** 协议版本号*/
            for(int i = 0; i < EasyChatMessage.getVersionContent().length; i++, index++) {
                if(bytes[index] != EasyChatMessage.getVersionContent()[i]) {
                    return;
                }
            }
            /** 目前消息编码类型仅有Json编码一种，暂时跳过这一字段*/
            index = index + 1;
            /** 消息类型*/
            byte msgType = bytes[index++];
            /** 消息本体的长度*/
            Integer msgLength = bytes2Int(bytes, index, index+4);
            index = index + 4;
            /** 消息本体*/
            Gson jsonUtils = new Gson();
            String json = new String(Arrays.copyOfRange(bytes, index, bytes.length-1), StandardCharsets.UTF_8);
            EasyChatRequest request = (EasyChatRequest) jsonUtils.fromJson(json, EasyChatRequest.getRequestType(msgType));
            request.setMsgDateTime(new Date());
            request.handlerMessage(socketChannel);
            index = bytes.length - 1;
            /** 结束符号*/
            if((index != bytes.length-1)||(bytes[index]!=0xff)) {
                return;
            }
        }
    }

    /**
     * 目前通讯协议的内容
     * 1. 魔数 6
     * 2. 通讯协议版本号 5
     * 3. 消息本体序列化方式 1
     * 4. 消息类型 1
     * 5. 消息本体长度 4
     * 6. 消息本体 1
     * 7. 结束符号 1
     * 3 4 5 6 7
     */
    /**
     * byte数组转化成数字
     * @param bytes 原来的byte数组
     * @return 转化过的数字
     */
    public Integer bytes2Int(byte[] bytes, int start, int end) {
        int value = 0;
        if(start + 4 == end) {
            int index1 = (bytes[start] & 0xff) << 24;
            int index2 = (bytes[start+1] & 0xff) << 16;
            int index3 = (bytes[start+2] & 0xff) << 8;
            int index4 = (bytes[start+3] & 0xff);
            value = index1 | index2 | index3 | index4;
        }
        return value;
    }

    /**
     * 数字转化为byte数组
     * @param value 原数字
     * @return 转化成的数组
     */
    public byte[] int2bytes(int value) {
        byte[] bytes = new byte[4];
        //由高位到低位
        bytes[0] = (byte)((value >> 24) & 0xFF);
        bytes[1] = (byte)((value >> 16) & 0xFF);
        bytes[2] = (byte)((value >> 8) & 0xFF);
        bytes[3] = (byte)(value & 0xFF);
        return bytes;
    }
}
